import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 贪吃蛇游戏主类
 * 包含游戏逻辑、图形界面和用户交互
 */
public class SnakeGame extends JFrame {
    // ==================== 游戏常量设置 ====================
    private static final int INITIAL_GRID_SIZE = 20;  // 初始网格尺寸（单位：格子数量）
    private static final int MAX_LENGTH = 350;        // 蛇的最大长度限制
    private static final Color DEFAULT_HEAD_COLOR = Color.GREEN;  // 默认蛇头颜色
    private static final Color DEFAULT_BODY_COLOR = Color.WHITE;  // 默认蛇身颜色
    private static final Color DEFAULT_FOOD_COLOR = Color.RED;   // 默认食物颜色
    private static final Color DEFAULT_BG_COLOR = Color.GRAY;    // 默认背景颜色

    // ==================== 组件声明 ====================
    private GamePanel gamePanel;        // 游戏绘制面板
    private JButton startButton;        // 开始游戏按钮
    private JButton restartButton;      // 重新开始按钮
    private JLabel statusLabel;         // 状态显示标签
    private JLabel speedLabel;          // 速度显示标签

    // ==================== 游戏状态变量 ====================
    private Direction currentDirection = Direction.RIGHT; // 当前移动方向
    private Direction nextDirection = Direction.RIGHT;    // 下一个方向（用于输入缓冲）
    private LinkedList<Point> snake = new LinkedList<>(); // 蛇身坐标集合
    private Point food;                // 食物坐标
    private volatile boolean gameRunning = false; // 游戏运行标志（volatile保证线程可见性）
    private final AtomicBoolean isPaused = new AtomicBoolean(false); // 暂停状态（原子操作）
    private Thread gameThread;          // 游戏主线程
    private final Lock snakeLock = new ReentrantLock(); // 蛇身访问锁（保证线程安全）

    // ==================== 用户配置 ====================
    private Color headColor = DEFAULT_HEAD_COLOR; // 蛇头颜色
    private Color bodyColor = DEFAULT_BODY_COLOR; // 蛇身颜色
    private Color foodColor = DEFAULT_FOOD_COLOR; // 食物颜色
    private Color bgColor = DEFAULT_BG_COLOR;     // 背景颜色
    private int baseSpeed = 150;        // 基础移动间隔（毫秒）
    private int speedLevel = 1;         // 当前速度等级
    // ==================== 动态布局参数 ====================
    private int cellSize;    // 单个格子像素尺寸
    private int gridSize;    // 可见区域尺寸（单位：格子数）
    
    // ==================== 方向枚举 ====================
    enum Direction { UP, DOWN, LEFT, RIGHT }

    /**
     * 构造函数：初始化游戏窗口和组件
     */
    public SnakeGame() {
        showColorSettings(); // 第一步：显示颜色设置对话框
        initUI();            // 初始化用户界面
        initGame();          // 初始化游戏数据
    }

    /**
     * 显示颜色设置对话框（用户自定义颜色配置）
     */
    private void showColorSettings() {
        // 创建颜色设置面板
        JPanel colorPanel = new JPanel(new GridLayout(4, 2));

        // 创建颜色选择按钮
        JButton headColorBtn = createColorButton("蛇头颜色", headColor);
        JButton bodyColorBtn = createColorButton("蛇身颜色", bodyColor);
        JButton foodColorBtn = createColorButton("食物颜色", foodColor);
        JButton bgColorBtn = createColorButton("背景颜色", bgColor);

        // 设置按钮点击事件
        headColorBtn.addActionListener(e ->
                headColor = JColorChooser.showDialog(this, "选择蛇头颜色", headColor));
        bodyColorBtn.addActionListener(e ->
                bodyColor = JColorChooser.showDialog(this, "选择蛇身颜色", bodyColor));
        foodColorBtn.addActionListener(e ->
                foodColor = JColorChooser.showDialog(this, "选择食物颜色", foodColor));
        bgColorBtn.addActionListener(e ->
                bgColor = JColorChooser.showDialog(this, "选择背景颜色", bgColor));

        // 组装面板
        colorPanel.add(new JLabel("颜色设置："));
        colorPanel.add(new JLabel());
        colorPanel.add(headColorBtn);
        colorPanel.add(bodyColorBtn);
        colorPanel.add(foodColorBtn);
        colorPanel.add(bgColorBtn);

        // 显示对话框
        JOptionPane.showMessageDialog(this, colorPanel, "颜色设置", JOptionPane.PLAIN_MESSAGE);
    }

    /**
     * 创建颜色选择按钮
     * @param text 按钮显示文字
     * @param color 初始颜色
     */
    private JButton createColorButton(String text, Color color) {
        JButton btn = new JButton(text);
        btn.setBackground(color);
        return btn;
    }

    /**
     * 初始化用户界面组件
     */
    private void initUI() {
        // 窗口设置
        setTitle("贪吃蛇游戏");
        setSize(1280, 720);
        setMinimumSize(new Dimension(400, 300));
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // 游戏绘制面板
        gamePanel = new GamePanel();
        gamePanel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                updateGridSize();    // 窗口大小改变时更新网格参数
                gamePanel.repaint(); // 重绘界面
            }
        });
        add(gamePanel, BorderLayout.CENTER);

        // 控制面板
        JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
        controlPanel.setBackground(Color.DARK_GRAY);

        // 状态标签
        statusLabel = new JLabel("按开始游戏启动");
        statusLabel.setFont(new Font("微软雅黑", Font.BOLD, 18));
        statusLabel.setForeground(Color.WHITE);

        // 按钮初始化
        startButton = new JButton("开始游戏");
        startButton.addActionListener(e -> startGame());

        restartButton = new JButton("再来一局");
        restartButton.addActionListener(e -> resetGame());
        restartButton.setVisible(false);

        // 速度标签
        speedLabel = new JLabel("速度：1");
        speedLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        speedLabel.setForeground(Color.WHITE);

        // 组装控制面板
        controlPanel.add(startButton);
        controlPanel.add(restartButton);
        controlPanel.add(statusLabel);

        // 游戏面板叠加组件
        gamePanel.setLayout(null);
        JButton pauseButton = new JButton("暂停");
        pauseButton.setBounds(10, 10, 80, 30);
        pauseButton.addActionListener(e -> showPauseDialog());
        gamePanel.add(pauseButton);

        gamePanel.add(speedLabel);
        speedLabel.setBounds(10, 50, 120, 30);

        add(controlPanel, BorderLayout.SOUTH);

        // 键盘事件监听
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                handleKeyPress(e.getKeyCode());
            }
        });

        setFocusable(true);
        setVisible(true);
    }

    /**
     * 更新网格尺寸（响应窗口大小变化）
     */
    private void updateGridSize() {
        int panelWidth = gamePanel.getWidth();
        int panelHeight = gamePanel.getHeight();
        gridSize = Math.min(panelWidth, panelHeight) / 30;  // 动态计算网格密度
        cellSize = Math.min(panelWidth, panelHeight) / gridSize; // 计算格子尺寸
    }

    /**
     * 处理键盘输入
     * @param keyCode 按键代码
     */
    private void handleKeyPress(int keyCode) {
        if (!gameRunning || isPaused.get()) return;

        // 方向键处理（防止180度转向）
        switch (keyCode) {
            case KeyEvent.VK_UP:
                if (currentDirection != Direction.DOWN) nextDirection = Direction.UP;
                break;
            case KeyEvent.VK_DOWN:
                if (currentDirection != Direction.UP) nextDirection = Direction.DOWN;
                break;
            case KeyEvent.VK_LEFT:
                if (currentDirection != Direction.RIGHT) nextDirection = Direction.LEFT;
                break;
            case KeyEvent.VK_RIGHT:
                if (currentDirection != Direction.LEFT) nextDirection = Direction.RIGHT;
                break;
            case KeyEvent.VK_SPACE:  // 空格键暂停
                showPauseDialog();
                break;
            case KeyEvent.VK_NUMPAD3: // 小键盘3加速
                adjustSpeed();
                break;
        }
    }

    /**
     * 初始化游戏数据（蛇和食物的初始位置）
     */
    private void initGame() {
        snakeLock.lock();
        try {
            // 初始化蛇身（水平排列）
            snake.clear();
            for (int i = 5; i >= 0; i--) {
                snake.add(new Point(i, INITIAL_GRID_SIZE/2));
            }
            generateFood(); // 生成第一个食物
        } finally {
            snakeLock.unlock();
        }
        updateGridSize();
    }

    /**
     * 开始游戏主循环
     */
    private void startGame() {
        // 重置游戏参数
        baseSpeed = 150;
        speedLevel = 1;
        speedLabel.setText("速度：1");

        gameRunning = true;
        startButton.setVisible(false);
        restartButton.setVisible(false);
        statusLabel.setText("游戏中... 长度: " + snake.size());

        // 创建游戏主线程
        gameThread = new Thread(() -> {
            long lastUpdate = System.currentTimeMillis();
            while (gameRunning) {
                if (!isPaused.get()) {
                    long now = System.currentTimeMillis();
                    // 定时更新游戏状态
                    if (now - lastUpdate >= baseSpeed) {
                        updateGameState();
                        lastUpdate = now;
                        SwingUtilities.invokeLater(gamePanel::repaint);
                    }
                }
                try {
                    Thread.sleep(5); // 降低CPU占用
                } catch (InterruptedException e) {
                    break;
                }
            }
        });
        gameThread.start();
    }

    /**
     * 更新游戏状态（移动、碰撞检测、食物检测）
     */
    private void updateGameState() {
        currentDirection = nextDirection; // 应用缓冲的方向

        snakeLock.lock();
        try {
            moveSnake();    // 移动蛇身
        } finally {
            snakeLock.unlock();
        }

        checkCollision();  // 碰撞检测
        checkFood();       // 食物检测
    }

    /**
     * 移动蛇头并处理身体
     */
    private void moveSnake() {
        Point head = snake.getFirst();
        Point newHead = new Point(head.x, head.y);

        // 根据方向计算新头部位置
        switch (currentDirection) {
            case UP:    newHead.y--; break;
            case DOWN:  newHead.y++; break;
            case LEFT:  newHead.x--; break;
            case RIGHT: newHead.x++; break;
        }

        snake.addFirst(newHead);
        if (snake.size() > MAX_LENGTH) gameOver(); // 达到最大长度游戏胜利
    }

    /**
     * 碰撞检测（边界和自碰撞）
     */
    private void checkCollision() {
        Point head;
        snakeLock.lock();
        try {
            head = snake.getFirst();
        } finally {
            snakeLock.unlock();
        }

        // 边界检测
        if (head.x < 0 || head.x >= INITIAL_GRID_SIZE ||
                head.y < 0 || head.y >= INITIAL_GRID_SIZE) {
            gameOver();
            return;
        }

        // 自碰撞检测
        snakeLock.lock();
        try {
            for (int i = 1; i < snake.size(); i++) {
                if (head.equals(snake.get(i))) {
                    gameOver();
                    return;
                }
            }
        } finally {
            snakeLock.unlock();
        }
    }

    /**
     * 食物检测与处理
     */
    private void checkFood() {
        snakeLock.lock();
        try {
            Point head = snake.getFirst();
            if (head.equals(food)) {
                generateFood();  // 吃到食物生成新位置
                SwingUtilities.invokeLater(() ->
                        statusLabel.setText("游戏中... 长度: " + snake.size()));
            } else {
                snake.removeLast(); // 未吃到食物则移动身体
            }
        } finally {
            snakeLock.unlock();
        }
    }

    /**
     * 生成新食物（确保不在蛇身上）
     */
    private void generateFood() {
        Random rand = new Random();
        do {
            food = new Point(
                    rand.nextInt(INITIAL_GRID_SIZE),
                    rand.nextInt(INITIAL_GRID_SIZE)
            );
        } while (snake.contains(food));
    }

    /**
     * 游戏结束处理
     */
    private void gameOver() {
        gameRunning = false;
        SwingUtilities.invokeLater(() -> {
            statusLabel.setText("游戏结束! 最终长度: " + snake.size());
            restartButton.setVisible(true);
        });
    }

    /**
     * 重置游戏状态
     */
    private void resetGame() {
        initGame();  // 重新初始化游戏数据
        currentDirection = Direction.RIGHT;
        nextDirection = Direction.RIGHT;
        restartButton.setVisible(false);
        startGame(); // 开始新游戏
    }

    /**
     * 显示暂停对话框
     */
    private void showPauseDialog() {
        if (!gameRunning) return;

        isPaused.set(true);
        Object[] options = {"继续游戏", "退出游戏"};
        int choice = JOptionPane.showOptionDialog(
                this,
                "游戏已暂停",
                "正在暂停中",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.INFORMATION_MESSAGE,
                null,
                options,
                options[0]
        );

        if (choice == 0) {
            isPaused.set(false); // 继续游戏
        } else {
            dispose();  // 退出程序
            System.exit(0);
        }
    }

    /**
     * 调整游戏速度
     */
    private void adjustSpeed() {
        if (baseSpeed > 50) {
            baseSpeed -= 10;  // 加速
            speedLevel++;
            speedLabel.setText("速度：" + speedLevel);
        }
    }

    /**
     * 自定义游戏绘制面板
     */
    class GamePanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            setBackground(bgColor);  // 设置背景颜色

            // 计算居中偏移量
            int panelWidth = getWidth();
            int panelHeight = getHeight();
            int offsetX = (panelWidth - gridSize * cellSize) / 2;
            int offsetY = (panelHeight - gridSize * cellSize) / 2;

            // 绘制网格线
            g.setColor(Color.LIGHT_GRAY);
            for (int i = 0; i <= gridSize; i++) {
                int x = offsetX + i * cellSize;
                int y = offsetY + i * cellSize;
                g.drawLine(x, offsetY, x, offsetY + gridSize * cellSize); // 垂直线
                g.drawLine(offsetX, y, offsetX + gridSize * cellSize, y); // 水平线
            }

            // 线程安全绘制蛇身
            snakeLock.lock();
            try {
                LinkedList<Point> snakeCopy = new LinkedList<>(snake);
                for (Point p : snakeCopy) {
                    // 区分头部和身体颜色
                    g.setColor(p == snakeCopy.getFirst() ? headColor : bodyColor);
                    int x = offsetX + p.x * cellSize + 1;
                    int y = offsetY + p.y * cellSize + 1;
                    g.fillRect(x, y, cellSize - 2, cellSize - 2);
                }
            } finally {
                snakeLock.unlock();
            }

            // 绘制食物
            if (food != null) {
                g.setColor(foodColor);
                int x = offsetX + food.x * cellSize + 1;
                int y = offsetY + food.y * cellSize + 1;
                g.fillRect(x, y, cellSize - 2, cellSize - 2);
            }
        }

    }

    /**
     * 程序入口
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new SnakeGame());
    }
}